package com.sky.service.userImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.properties.BaiduMapProperties;
import com.sky.result.PageResult;
import com.sky.service.AddressBookService;
import com.sky.service.OrderService;
import com.sky.service.ShoppingCartService;
import com.sky.utils.BaiduMapUtil;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.Map.Entry;import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ShoppingCartService shoppingCartService;
    @Autowired
    private AddressBookService addressBookService;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private BaiduMapUtil baiduMapUtil;
    @Autowired
    private BaiduMapProperties baiduMapProperties;
    @Autowired
    private WebSocketServer webSocketServer;
    /**
     * 客户提交订单
     * @param ordersSubmitDTO
     * @return
     */
    @Override
    @Transactional
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //业务异常处理
        //购物车数据为空,不能下单
        List<ShoppingCart> shoppingCarts = shoppingCartService.get();
        if (shoppingCarts==null||shoppingCarts.isEmpty()){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //地址薄为空,不能下单
        AddressBook addressBook = addressBookService.getById(ordersSubmitDTO.getAddressBookId());
        if (addressBook==null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        // 地址薄的地址是否超出配送范围?(5公里)
        // 商家地址经纬度
        String shopCodingJSONResult = baiduMapUtil.geocoding(baiduMapProperties.getShop());

        JSONObject shopCodingResult = JSON.parseObject(shopCodingJSONResult);
        if (!"0".equals(shopCodingResult.getString("status"))){
            throw new OrderBusinessException(MessageConstant.SHOP_GET_FAILED);
        }
        JSONObject shopLocationResult = shopCodingResult.getJSONObject("result").getJSONObject("location");
        String shopLng = shopLocationResult.getString("lng");
        String shopLat = shopLocationResult.getString("lat");
        // 解析后的商家地址经纬度
        String shopLocation = shopLat + "," + shopLng;

        // 用户地址经纬度
        String userCodingJSONResult = baiduMapUtil.geocoding(addressBook.getProvinceName() + addressBook.getCityName()
                + addressBook.getDistrictName() + addressBook.getDetail());

        JSONObject userCodingResult = JSON.parseObject(userCodingJSONResult);
        if (!"0".equals(userCodingResult.getString("status"))){
            throw new OrderBusinessException(MessageConstant.USER_GET_FAILED);
        }
        JSONObject userLocationResult = userCodingResult.getJSONObject("result").getJSONObject("location");
        String userLng = userLocationResult.getString("lng");
        String userLat = userLocationResult.getString("lat");
        // 解析后的用户地址经纬度
        String userLocation =  userLat + "," + userLng;


        // 获取两个地址经纬度之间的路线规划
        String liteJSONResult = baiduMapUtil.directionLiteDriver(shopLocation, userLocation);
        JSONObject liteResult = JSON.parseObject(liteJSONResult);
        if (!"0".equals(liteResult.getString("status"))){
            System.out.println(liteResult.getString("status")+liteResult.getString("message"));
            throw new OrderBusinessException(MessageConstant.GET_LITE_FAILED);
        }
        JSONArray routes = liteResult.getJSONObject("result").getJSONArray("routes");
        Integer distance=(Integer) ((JSONObject) routes.get(0)).get("distance");
        // 距离大于五公里,就不能配送
        /**
         * 测试通过,前端没有对应展示,不启用
         */
        if (distance>5000){
//            throw new  OrderBusinessException(MessageConstant.OUT_DISTANCE);
        }


        //提交的是用户的购物车中的菜品套餐数据
        //订单信息插入订单表
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        orders.setOrderTime(LocalDateTime.now());
        orders.setUserId(BaseContext.get());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setNumber(StringUtils.delete(UUID.randomUUID().toString(),"-"));
        orders.setPhone(addressBook.getPhone());
        orders.setAddress(addressBook.getDetail());
        orders.setConsignee(addressBook.getConsignee());;
        orderMapper.insert(orders);
        //购物车数据插入订单详情表
        List<OrderDetail> orderDetailList=new ArrayList<>();
        shoppingCarts.forEach(shoppingCart -> {
            OrderDetail orderDetail=new OrderDetail();
            BeanUtils.copyProperties(shoppingCart,orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetailList.add(orderDetail);
        });
        orderDetailMapper.insert(orderDetailList);
        //清空购物车
        shoppingCartService.clean();
        //封装VO
        return OrderSubmitVO.builder()
                .id(orders.getId())
                .orderAmount(orders.getAmount())
                .orderNumber(orders.getNumber())
                .orderTime(orders.getOrderTime())
                .build();
    }

    /**
     * 订单支付（未启用）
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
//         当前登录用户id
//        Long userId = BaseContext.get();
//        User user = userMapper.getById(userId);
//
//        调用微信支付接口，生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额，单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }
//        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
//        vo.setPackageStr(jsonObject.getString("package"));

        /**
         * 跳过微信支付直接修改订单状态
         */
        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(ordersPaymentDTO.getOrderNumber());
        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders=new Orders();
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setPayStatus(Orders.PAID);
        orders.setCheckoutTime(LocalDateTime.now());
        orderMapper.update(orders);
        // 下单提醒
        // 约定服务端
        Map<String,Object> params = new HashMap<>();
        params.put("type",1);
        params.put("orderId",ordersDB.getId());
        params.put("content","订单号："+ordersDB.getId());

        String message = JSON.toJSONString(params);
        webSocketServer.broadCast(message);
        return new OrderPaymentVO();
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {
       /* // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders=new Orders();
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setPayStatus(Orders.PAID);
        orders.setCheckoutTime(LocalDateTime.now());
        orderMapper.update(orders);*/
    }

    /**
     * 客户获取订单和订单详情
     * @param id
     * @return
     */
    @Override
    public OrderVO getDetail(Long id) {
        OrderVO orderVO = new OrderVO();
        Orders orders=orderMapper.getById(id);
        BeanUtils.copyProperties(orders,orderVO);

        List<OrderDetail> orderDetailList=orderDetailMapper.getByOrderId(id);
        orderVO.setOrderDetailList(orderDetailList);

        String orderDishesString = getOrderDishesString(orderDetailList);
        orderVO.setOrderDishes(orderDishesString);
        return orderVO;
    }

    /**
     * 客户取消订单
     * 待支付1和待接单状态2可以取消，已接单3和派送状态4需要电话沟通商家
     * 大于2状态不能取消.待接单状态下取消，需要退款
     * @param id
     */
    @Override
    public void cancelOrder(Long id) {
        //设置取消原因
        Orders orderDB = orderMapper.getById(id);
        Orders order = new Orders();

        if (orderDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        // 如果订单状态大于2(待接单)不能取消
        if (orderDB.getStatus()>Orders.TO_BE_CONFIRMED){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        // 支付状态是已付款,需要退款
        if (orderDB.getStatus().equals(Orders.PAID)){
            //调用微信接口退款处理

            //支付状态改为退款
            order.setPayStatus(Orders.REFUND);
        }
        order.setId(orderDB.getId());
        order.setCancelReason("客户取消");
        order.setStatus(Orders.CANCELLED);
        order.setCancelTime(LocalDateTime.now());
        orderMapper.update(order);
    }

    /**
     * 客户分页搜索自己的订单
     * @param pageQueryDTO
     * @return
     */
    @Override
    public PageResult<OrderVO> getOrders(OrdersPageQueryDTO pageQueryDTO) {
        //历史订单
        PageResult<OrderVO> pageResult = new PageResult<>();
        PageHelper.startPage(pageQueryDTO.getPage(),pageQueryDTO.getPageSize());
        //查询的是用户自己的订单
        pageQueryDTO.setUserId(BaseContext.get());
        List<OrderVO> ordersList=orderMapper.selectPage(pageQueryDTO);
        //将查询到的订单封装为Page
        Page<OrderVO> orderVOPage=(Page<OrderVO>) ordersList;
        //如果有订单,根据每个订单号查询订单的详情菜品,设置到VO中
        if (orderVOPage!=null&&!orderVOPage.isEmpty()) {
            orderVOPage.forEach(orderVO -> {
                Long id = orderVO.getId();
                List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
                orderVO.setOrderDetailList(orderDetailList);
            });
            pageResult.setTotal(orderVOPage.getTotal());
            pageResult.setRecords(orderVOPage.getResult());
        }
        return pageResult;
    }

    /**
     * 客户再来一单
     * @param id
     */
    @Override
    public void repetitionOrder(Long id) {
        //查询订单id,看有没有这单
        Orders order = orderMapper.getById(id);
        if (order==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        //获取订单详情放到购物车里
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
        List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(x->{
            ShoppingCart shoppingCart = new ShoppingCart();

            BeanUtils.copyProperties(x,shoppingCart,"id");
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCart.setUserId(BaseContext.get());

            return shoppingCart;
        }).collect(Collectors.toList());

        shoppingCartMapper.insertBatches(shoppingCartList);
    }

    /**
     * 商家分页搜索不同状态的订单
     * @param pageQueryDTO
     * @return
     */
    @Override
    public PageResult<OrderVO> searchOrders(OrdersPageQueryDTO pageQueryDTO) {
        // 查询订单
        PageResult<OrderVO> pageResult = new PageResult<>();
        PageHelper.startPage(pageQueryDTO.getPage(),pageQueryDTO.getPageSize());
        List<OrderVO> ordersList=orderMapper.selectPage(pageQueryDTO);
        //将查询到的订单封装为Page
        Page<OrderVO> orderVOPage=(Page<OrderVO>) ordersList;
        //如果有订单,根据每个订单号查询订单的详情菜品,设置到VO中
        if (orderVOPage!=null&&!orderVOPage.isEmpty()) {
            //遍历分页中的订单
            orderVOPage.forEach(orderVO -> {
                //查询每个订单的详情菜品
                Long id = orderVO.getId();
                List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
                String orderDishesString = getOrderDishesString(orderDetailList);
                orderVO.setOrderDishes(orderDishesString);
            });
            pageResult.setTotal(orderVOPage.getTotal());
            pageResult.setRecords(orderVOPage.getResult());
        }
        //配置字符串订单菜品信息

        return pageResult;
    }

    /**
     * 获取每个状态的订单数量
     * @return
     */
    @Override
    public OrderStatisticsVO getStatistics() {
        //待接单数
        Integer statistics2 = orderMapper.getStatistics(Orders.TO_BE_CONFIRMED);
        //已接单(待派送数)
        Integer statistics3 = orderMapper.getStatistics(Orders.CONFIRMED);
        //派送中数
        Integer statistics4 = orderMapper.getStatistics(Orders.DELIVERY_IN_PROGRESS);

        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        orderStatisticsVO.setConfirmed(statistics3);
        orderStatisticsVO.setToBeConfirmed(statistics2);
        orderStatisticsVO.setDeliveryInProgress(statistics4);
        return orderStatisticsVO;
    }

    /**
     * 商家确认接单
     * @param ordersConfirmDTO
     */
    @Override
    public void confirmOrder(OrdersConfirmDTO ordersConfirmDTO) {
        Orders order = new Orders();
        order.setId(ordersConfirmDTO.getId());
        order.setStatus(Orders.CONFIRMED);
        orderMapper.update(order);
    }

    /**
     * 商家拒绝接单
     * 待接单才能拒单,付款状态需要退款
     * @param ordersRejectionDTO
     */
    @Override
    public void rejectOrder(OrdersRejectionDTO ordersRejectionDTO) {

        Orders orderDB = orderMapper.getById(ordersRejectionDTO.getId());

        Orders order = new Orders();

        if (orderDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!orderDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        if (orderDB.getPayStatus().equals(Orders.PAID)){
            //调用微信接口退款处理

            //支付状态改为退款
            order.setPayStatus(Orders.REFUND);
        }
        order.setStatus(Orders.CANCELLED);
        order.setId(orderDB.getId());
        order.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        order.setCancelTime(LocalDateTime.now());
        orderMapper.update(order);
    }

    /**
     * 商家派送订单
     * @param orderId
     */
    @Override
    public void deliverOrder(Long orderId) {
        Orders orderDB = orderMapper.getById(orderId);
        if (orderDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!Objects.equals(orderDB.getStatus(), Orders.CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = new Orders();
        orders.setId(orderDB.getId());
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        orderMapper.update(orders);
    }

    /**
     * 商家取消订单
     * 待接单不能取消订单
     * @param ordersCancelDTO
     */
    @Override
    public void adminCancelOrder(OrdersCancelDTO ordersCancelDTO) {
        Orders orderDB = orderMapper.getById(ordersCancelDTO.getId());
        Orders order = new Orders();
        if (orderDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (orderDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        if (orderDB.getPayStatus().equals(Orders.PAID)) {
            //调用微信接口退款处理
            //支付状态改为退款
            order.setPayStatus(Orders.REFUND);
        }
        order.setId(ordersCancelDTO.getId());
        order.setCancelReason(ordersCancelDTO.getCancelReason());
        order.setCancelTime(LocalDateTime.now());
        order.setStatus(Orders.CANCELLED);

        orderMapper.update(order);
    }

    /**
     * 商家完成订单
     * 只有派送中订单可以完成 4
     * @param id
     */
    @Override
    public void completeOrder(Long id) {
        Orders orderDB = orderMapper.getById(id);
        if (orderDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!orderDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders order = new Orders();
        order.setId(orderDB.getId());
        order.setStatus(Orders.COMPLETED);
        order.setDeliveryTime(LocalDateTime.now());
        orderMapper.update(order);
    }

    /**
     * 客户催单
     * 待接单才能催单
     * @param id
     */
    @Override
    public void reminderOrder(Long id) {
        Orders ordersDB = orderMapper.getById(id);
        if (ordersDB==null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        if (!ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        // 催单
        // 约定服务端
        Map<String,Object> params = new HashMap<>();
        params.put("type",2);
        params.put("orderId",ordersDB.getId());
        params.put("content","订单号："+ordersDB.getId());

        String message = JSON.toJSONString(params);
        webSocketServer.broadCast(message);
    }


    /**
     * 私有公共方法: 获取订单详情菜品的字符串(toString)
     * @param orderDetailList
     * @return
     */
    private String getOrderDishesString(List<OrderDetail> orderDetailList){
        List<String> orderDishes = orderDetailList.stream().map(
                orderDetail -> orderDetail.getName()+
                        '*'+orderDetail.getNumber() +';'
        ).collect(Collectors.toList());
        return String.join("", orderDishes);
    }









}



